from fastapi import APIRouter, Depends, UploadFile, File, Form, HTTPException, Request
from fastapi.responses import StreamingResponse, FileResponse
from sqlalchemy.orm import Session
from typing import List
import os
import aiofiles
import asyncio

from ..database import get_db
from ..models.video import Video
from ..schemas import video as schemas
from ..utils.file_handler import save_upload_file, save_file_chunk, merge_chunks, delete_file, get_file_size, create_temp_upload_dir
from ..utils.logger import setup_logger
from ..config import VIDEO_DIR, STATIC_FILES_DIR

# 创建日志记录器
logger = setup_logger()

router = APIRouter()

CHUNK_SIZE = 1024 * 1024  # 1MB
CACHE_DIR = "cache"  # 缓存目录

# 确保缓存目录存在
if not os.path.exists(CACHE_DIR):
    os.makedirs(CACHE_DIR)

async def video_stream_with_cache(video_path: str, cache_path: str, start: int = 0):
    """视频流生成器，支持边下载边缓存"""
    try:
        # 检查缓存是否存在
        if os.path.exists(cache_path):
            cache_size = os.path.getsize(cache_path)
            logger.info(f"发现缓存文件 - 路径: {cache_path}, 大小: {format_file_size(cache_size)}")
            
            async with aiofiles.open(cache_path, 'rb') as f:
                await f.seek(start)
                bytes_sent = 0
                while chunk := await f.read(CHUNK_SIZE):
                    bytes_sent += len(chunk)
                    yield chunk
                
            logger.info(f"缓存读取完成 - 文件: {os.path.basename(cache_path)}, 总传输: {format_file_size(bytes_sent)}")
            return

        # 缓存不存在，边读边缓存
        logger.info(f"未找到缓存，开始创建 - 路径: {cache_path}")
        bytes_cached = 0
        bytes_sent = 0
        
        async with aiofiles.open(video_path, 'rb') as source, \
                   aiofiles.open(cache_path, 'wb') as cache:
            await source.seek(start)
            while chunk := await source.read(CHUNK_SIZE):
                await cache.write(chunk)
                await cache.flush()  # 确保数据写入磁盘
                
                bytes_cached += len(chunk)
                bytes_sent += len(chunk)
                yield chunk
                
                if bytes_cached % (10 * CHUNK_SIZE) == 0:  # 每10MB记录一次
                    logger.info(f"缓存进度 - 已缓存: {format_file_size(bytes_cached)}, 已发送: {format_file_size(bytes_sent)}")

        logger.info(f"缓存创建完成 - 文件: {os.path.basename(cache_path)}, "
                   f"总大小: {format_file_size(bytes_cached)}, 总传输: {format_file_size(bytes_sent)}")

    except Exception as e:
        logger.error(f"视频流处理错误 - 文件: {os.path.basename(video_path)}, 错误: {str(e)}", exc_info=True)
        if os.path.exists(cache_path):
            try:
                os.remove(cache_path)
                logger.info(f"已清理损坏的缓存文件: {cache_path}")
            except Exception as cleanup_error:
                logger.error(f"清理缓存文件失败: {cleanup_error}")
        raise HTTPException(status_code=500, detail="视频流处理错误")

@router.post("/upload/", response_model=schemas.Video)
async def upload_video(
    title: str = Form(...),
    file: UploadFile = File(...),
    db: Session = Depends(get_db)
):
    logger.info(f"收到视频上传请求 - 标题: {title}, 文件名: {file.filename}")
    
    if not title or not title.strip():
        logger.warning(f"上传失败 - 标题为空")
        raise HTTPException(status_code=422, detail="Title cannot be empty")
    
    if not file:
        logger.warning(f"上传失败 - 未选择文件")
        raise HTTPException(status_code=422, detail="No file uploaded")

    if not file.filename:
        logger.warning(f"上传失败 - 文件名为空")
        raise HTTPException(status_code=422, detail="No filename provided")

    try:
        filename = f"{title}_{file.filename}"
        logger.info(f"开始保存文件 - 文件名: {filename}")
        
        file_path = await save_upload_file(file, filename)
        file_size = os.path.getsize(file_path)
        
        logger.info(f"文件保存成功 - 路径: {file_path}, 大小: {file_size} bytes")
        
        db_video = Video(
            title=title,
            filename=filename,
            file_path=file_path,
            file_size=file_size
        )
        
        logger.info("开始写入数据库...")
        db.add(db_video)
        db.commit()
        db.refresh(db_video)
        
        logger.info(f"视频上传完成 - ID: {db_video.id}, 标题: {title}, 大小: {format_file_size(file_size)}")
        return db_video
        
    except Exception as e:
        logger.error(f"视频上传失败 - 标题: {title}, 文件名: {file.filename}, 错误: {str(e)}", exc_info=True)
        # 如果文件已保存，尝试清理
        if 'file_path' in locals() and os.path.exists(file_path):
            try:
                os.remove(file_path)
                logger.info(f"已清理失败的上传文件: {file_path}")
            except Exception as cleanup_error:
                logger.error(f"清理失败的上传文件出错: {cleanup_error}")
        raise HTTPException(status_code=500, detail=str(e))

def format_file_size(size):
    """格式化文件大小"""
    for unit in ['B', 'KB', 'MB', 'GB']:
        if size < 1024:
            return f"{size:.2f} {unit}"
        size /= 1024
    return f"{size:.2f} TB"

@router.get("/videos/", response_model=List[schemas.Video])
async def get_videos(
    skip: int = 0,
    limit: int = 10,
    db: Session = Depends(get_db)
):
    videos = db.query(Video).offset(skip).limit(limit).all()
    return videos

@router.get("/video/{video_id}")
async def get_video(video_id: int, request: Request, db: Session = Depends(get_db)):
    """获取视频流，支持缓存和断点续传"""
    logger.info(f"收到视频请求 - ID: {video_id}")
    try:
        # 从数据库获取视频信息
        video = db.query(Video).filter(Video.id == video_id).first()
        if not video:
            logger.error(f"视频不存在 - ID: {video_id}")
            raise HTTPException(status_code=404, detail="视频不存在")

        video_path = video.file_path
        logger.info(f"视频信息 - 标题: {video.title}, 路径: {video_path}")
        
        if not os.path.exists(video_path):
            logger.error(f"视频文件丢失 - 路径: {video_path}")
            raise HTTPException(status_code=404, detail="视频文件不存在")

        # 生成缓存文件路径
        cache_filename = os.path.basename(video_path)
        cache_path = os.path.join(CACHE_DIR, cache_filename)

        # 获取请求头中的 Range
        range_header = request.headers.get("range")
        start = 0

        if range_header:
            try:
                start_str = range_header.split("=")[1].split("-")[0]
                start = int(start_str) if start_str else 0
                logger.info(f"断点续传请求 - 起始位置: {start} bytes")
            except Exception as e:
                logger.warning(f"Range header 解析失败: {range_header}, 错误: {e}")
                start = 0

        # 获取视频文件大小
        file_size = os.path.getsize(video_path)
        logger.info(f"视频大小: {format_file_size(file_size)}")

        # 设置响应头
        headers = {
            "Accept-Ranges": "bytes",
            "Content-Type": "video/mp4",
        }

        if range_header:
            headers["Content-Range"] = f"bytes {start}-{file_size-1}/{file_size}"
            status_code = 206
            logger.info(f"断点续传响应 - 范围: bytes {start}-{file_size-1}/{file_size}")
        else:
            status_code = 200
            logger.info("完整视频请求")

        # 返回视频流
        return StreamingResponse(
            video_stream_with_cache(video_path, cache_path, start),
            headers=headers,
            status_code=status_code
        )

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"视频流处理错误 - ID: {video_id}, 错误: {str(e)}", exc_info=True)
        raise HTTPException(status_code=500, detail="获取视频流错误")

@router.delete("/video/{video_id}")
async def delete_video(video_id: int, db: Session = Depends(get_db)):
    """删除视频及其相关资源"""
    logger.info(f"收到删除请求 - 视频ID: {video_id}")
    
    video = db.query(Video).filter(Video.id == video_id).first()
    if not video:
        logger.warning(f"删除失败 - 视频不存在: {video_id}")
        raise HTTPException(status_code=404, detail="Video not found")
    
    try:
        # 记录要删除的视频信息
        logger.info(f"开始删除视频 - ID: {video_id}, 标题: {video.title}, "
                   f"文件: {video.filename}, 大小: {format_file_size(video.file_size)}")
        
        # 删除原始文件
        if os.path.exists(video.file_path):
            os.remove(video.file_path)
            logger.info(f"原始文件已删除 - 路径: {video.file_path}")
        else:
            logger.warning(f"原始文件不存在 - 路径: {video.file_path}")
        
        # 删除缓存文件
        cache_path = os.path.join(CACHE_DIR, os.path.basename(video.file_path))
        if os.path.exists(cache_path):
            try:
                os.remove(cache_path)
                logger.info(f"缓存文件已删除 - 路径: {cache_path}")
            except Exception as e:
                logger.error(f"删除缓存文件失败 - 路径: {cache_path}, 错误: {str(e)}")
        
        # 删除数据库记录
        logger.info(f"开始删除数据库记录 - ID: {video_id}")
        db.delete(video)
        db.commit()
        logger.info(f"视频删除成功 - ID: {video_id}, 标题: {video.title}")
        
        return {
            "message": "Video deleted successfully",
            "details": {
                "id": video_id,
                "title": video.title,
                "filename": video.filename,
                "size": format_file_size(video.file_size)
            }
        }
        
    except Exception as e:
        logger.error(f"删除视频失败 - ID: {video_id}, 错误: {str(e)}", exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))
